package com.example.demo.socket;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class MyServer1 {

    //改进服务端
    public static void main(String[] args) throws Exception {

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //设置serverSocketChannel的accept方法为非阻塞
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.bind(new InetSocketAddress(8000));
        List<SocketChannel> channelList = new ArrayList<>();
        //3、接收客户端连接
        ByteBuffer buffer = ByteBuffer.allocate(20);
        while (true) {
//            System.out.println("等待连接");
            SocketChannel socketChannel = serverSocketChannel.accept();
//            System.out.println("accept = " + accept);
//            System.out.println("连接上了");
            if (socketChannel != null) {
                //设置socketChannel为非阻塞
                socketChannel.configureBlocking(false);
                channelList.add(socketChannel);
            }
            //client与服务端的通信过程 NIO代码
//            System.out.println("准备遍历list");
            for (SocketChannel channel : channelList) {
//                System.out.println("开始遍历channelList....");
                int read = channel.read(buffer);//阻塞 对应的IO通信的阻塞
                if (read>0){
                    buffer.flip();
                    CharBuffer decode = StandardCharsets.UTF_8.decode(buffer);

                    System.out.println("decode.toString() = " + decode.toString());
                    buffer.clear();
                }

//                System.out.println("结束本次遍历channelList....");
            }
        }
    }

    /*
    * 本次改进只是解决了accept的阻塞，然而channel的read阻塞并未解决
    * 由此会产生一些棘手的小问题
    * 1、显而易见的问题是accept虽然不再阻塞，read阻塞，每次便利channelList的时候，只要第一个channel中没有新数据进来，就会阻塞在这里
    *    如果第一个通道有数据，遍历完拿完第一个通道的数据，遍历很快就会过去，以至于来不及让第二个通道的数据发送过来，即使发送过来，遍历也过去了
    *    2 通道的数据会在下一次1 通道发完数据后，迟来的打印
    * 2、按道理 应该是按照上面的逻辑，但是经过测试，有时候顺序会错乱
    *
    * 紧接着 把socketChannel设置为非阻塞
    *
    * 但是又会产生空转问题，CPU飙升，后患无穷
    * 那么如何更细粒度控制代码流程
    * 为了让流程更加理性，必须引入监管机制
    * 就是，当对象触发了什么状态才会操作他
    * */

}
